package simulateOS.controller;

import javafx.animation.PathTransition;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.css.StyleOrigin;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.util.Callback;
import javafx.util.Duration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import simulateOS.MainApplication;
import simulateOS.entity.*;
import simulateOS.entity.Process;
import simulateOS.management.computerInterface.MemoryInterface;
import simulateOS.management.computerInterface.ProcessInterface;
import simulateOS.utils.RuntimeTimer;

import javax.annotation.Resource;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Description：
 * Date: 2022/10/25
 * Time: 20:46
 *
 * @Author SillyBaka
 **/
@Service
@Controller
@Component
public class ProcessPageController implements Initializable {

    @FXML
    private TableView<Process> runtimeProcessQueue;
    @FXML
    private TableView<Process> readyProcessQueueTableView;
    @FXML
    private TableView<Process> blockingProcessQueueTableView;
    @FXML
    private TableView<Process> endProcessTableView;
    @FXML
    private FlowPane memoryPane;
    @FXML
    private AnchorPane processPagePane;
    @FXML
    private Button createProcessBtn;
    @FXML
    private Button startBtn;
    @FXML
    private Label runTimeLabel;
    @FXML
    private Button allocateBtn;
    @FXML
    private Button releaseBtn;

    private Rectangle ready2RunRec;

    private Rectangle run2ReadyRec;

    private Rectangle run2BlockRec;

    private Rectangle block2ReadyRec;

    private PathTransition ready2RunPt;

    private PathTransition run2BlockPt;

    private PathTransition run2ReadyPt;

    private PathTransition block2ReadyPt;


    @Resource
    private ProcessInterface processManager;
    @Resource
    private MemoryInterface memoryManager;
    /**
     * 系统运行时间计时器
     */
    @Resource
    private RuntimeTimer runtimeTimer;
    /**
     * spring上下文
     */
    private ConfigurableApplicationContext applicationContext;
    /**
     * 内存块512个
     */
    private final ObservableList<Rectangle> memoryRecList;
    /**
     * 线程池
     */
    private final Executor poolExecutor = new ThreadPoolExecutor(4,4,15, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    /**
     * 用于存放就绪进程列表
     */
    private final ObservableList<Process> readyProcessList = FXCollections.observableArrayList();
    /**
     * 用于存放阻塞进程列表
     */
    private final ObservableList<Process> blockingProcessList = FXCollections.observableArrayList();
    /**
     * 用于记录已运行完毕的线程，可能有运行重复的文件
     */
    private final ObservableList<Process> endingProcessList = FXCollections.observableArrayList();

    public ProcessPageController(){
        // 初始化内存块列表 512个
        memoryRecList = FXCollections.observableList(new ArrayList<>());
        for (int i = 0; i < 512; i++) {
            Rectangle rectangle = new Rectangle(15, 15,Color.LIGHTGREY);
            memoryRecList.add(rectangle);
        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // 将组件按需注入IOC容器
        this.applicationContext = MainApplication.applicationContext;

        memoryPane.getChildren().addAll(memoryRecList);

        // 提交异步线程任务
        runtimeTimer.start();

        // 初始化进程队列
        initTableView();

        // 初始化进程动画
        initAnimation();

    }


    @FXML
    public void createProcess(){
        processManager.createProcess(null);
    }
    @FXML
    public void startProcess(){
        processManager.startToRun();
    }

    @FXML
    public void jobManage(){

    }


    /**
     * 初始化就绪队列和阻塞队列的TableView
     */
    public void initTableView(){

        readyProcessQueueTableView.setItems(readyProcessList);
        blockingProcessQueueTableView.setItems(blockingProcessList);

        // 添加运行态时更改行颜色
        readyProcessQueueTableView.setRowFactory(param -> new MyTableRow());
        blockingProcessQueueTableView.setRowFactory(param -> new MyTableRow());


        List<TableColumn<Process, ?>> readyProcessQueueColumnList = getProcessQueueTableColumn();
        List<TableColumn<Process, ?>> blockingProcessQueueColumnList = getProcessQueueTableColumn();

        readyProcessQueueTableView.getColumns().addAll(readyProcessQueueColumnList);
        blockingProcessQueueTableView.getColumns().addAll(blockingProcessQueueColumnList);

        endProcessTableView.setItems(endingProcessList);

        TableColumn<Process, Integer> pidColumn = new TableColumn<>("曾经的进程号");
        pidColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Process, Integer>, ObservableValue<Integer>>() {
            @Override
            public ObservableValue<Integer> call(TableColumn.CellDataFeatures<Process, Integer> param) {
                return new SimpleObjectProperty<>(param.getValue().getPcb().getPid());
            }
        });

        TableColumn<Process, Integer> resultColumn = new TableColumn<>("运行结果");
        resultColumn.setCellValueFactory(new PropertyValueFactory<>("runResult"));

        endProcessTableView.getColumns().addAll(pidColumn,resultColumn);
    }

    private List<TableColumn<Process, ?>> getProcessQueueTableColumn() {

        List<TableColumn<Process,?>> columnList = new ArrayList<>();

        TableColumn<Process,Integer> pidColumn = new TableColumn<>("进程名");
        pidColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Process, Integer>, ObservableValue<Integer>>() {
            @Override
            public ObservableValue<Integer> call(TableColumn.CellDataFeatures<Process, Integer> param) {
                return new SimpleObjectProperty<>(param.getValue().getPcb().getPid());
            }
        });
        columnList.add(pidColumn);

        TableColumn<Process, Status> statusColumn = new TableColumn<>("进程状态");
        statusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
        columnList.add(statusColumn);

        TableColumn<Process,Number> runResultColumn = new TableColumn<>("运行结果");
        runResultColumn.setCellValueFactory(new PropertyValueFactory<>("runResult"));
        columnList.add(runResultColumn);

        TableColumn<Process, Double>  column_progress = new TableColumn<Process, Double>("进度条");
        column_progress.setCellValueFactory(new PropertyValueFactory("progressBar"));
        columnList.add(column_progress);


        TableColumn<Process,String> device = new TableColumn<>("设备");
        device.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Process, String>, ObservableValue<String>>() {
            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<Process, String> param) {
                return new SimpleObjectProperty<>(param.getValue().getDevice().getDeviceName());
            }
        });
        columnList.add(device);

        return columnList;
    }

    // 初始化进程移动的动画
    public void initAnimation(){
        Path ready2RunPath = new Path();
        MoveTo m1 = new MoveTo(400,570);
        LineTo l1= new LineTo(400, 463);
        MoveTo m11 = new MoveTo(400,463);
        LineTo l11 = new LineTo(561, 463);
        ready2RunPath.getElements().addAll(m1,l1,m11,l11);
        processPagePane.getChildren().add(ready2RunPath);

        Path run2BlockPath = new Path();
        MoveTo m2 = new MoveTo(739,463);
        LineTo l2 = new LineTo(900, 463);
        MoveTo m22 = new MoveTo(900,463);
        LineTo l22 = new LineTo(900, 570);
        run2BlockPath.getElements().addAll(m2,l2,m22,l22);
        processPagePane.getChildren().add(run2BlockPath);

        Path run2ReadyPath = new Path();
        MoveTo m3 = new MoveTo(561,463);
        LineTo l3 = new LineTo(400, 463);
        MoveTo m33 = new MoveTo(400,463);
        LineTo l33= new LineTo(400, 570);
        run2ReadyPath.getElements().addAll(m3,l3,m33,l33);
        processPagePane.getChildren().add(run2ReadyPath);

        Path block2ReadyPath = new Path();
        MoveTo m4 = new MoveTo(713,683);
        LineTo l4 = new LineTo(584,683);
        block2ReadyPath.getElements().addAll(m4,l4);
        processPagePane.getChildren().add(block2ReadyPath);

        ready2RunRec = new Rectangle(50, 50, Color.PINK);
        ready2RunRec.setVisible(false);

        run2ReadyRec = new Rectangle(50, 50, Color.BROWN);
        run2ReadyRec.setVisible(false);

        run2BlockRec = new Rectangle(50, 50, Color.YELLOW);
        run2BlockRec.setVisible(false);

        block2ReadyRec = new Rectangle(50, 50, Color.PINK);
        block2ReadyRec.setVisible(false);

        processPagePane.getChildren().add(ready2RunRec);
        processPagePane.getChildren().add(run2ReadyRec);
        processPagePane.getChildren().add(run2BlockRec);
        processPagePane.getChildren().add(block2ReadyRec);

        ready2RunPt = new PathTransition();
        ready2RunPt.setDuration(Duration.millis(370));
        ready2RunPt.setPath(ready2RunPath);
        ready2RunPt.setNode(ready2RunRec);
        // 默认-- 动画完成时隐藏方块
        ready2RunPt.setOnFinished(event -> ready2RunRec.setVisible(false));

        run2BlockPt = new PathTransition();
        run2BlockPt.setDuration(Duration.millis(700));
        run2BlockPt.setPath(run2BlockPath);
        run2BlockPt.setNode(run2BlockRec);
        // 默认-- 动画完成时隐藏方块
        run2BlockPt.setOnFinished(event -> run2BlockRec.setVisible(false));

        run2ReadyPt = new PathTransition();
        run2ReadyPt.setDuration(Duration.millis(370));
        run2ReadyPt.setPath(run2ReadyPath);
        run2ReadyPt.setNode(run2ReadyRec);
        // 默认-- 动画完成时隐藏方块
        run2ReadyPt.setOnFinished(event -> run2ReadyRec.setVisible(false));

        block2ReadyPt = new PathTransition();
        block2ReadyPt.setDuration(Duration.millis(700));
        block2ReadyPt.setPath(block2ReadyPath);
        block2ReadyPt.setNode(block2ReadyRec);
        block2ReadyPt.setOnFinished(event -> block2ReadyRec.setVisible(false));

    }


    /**
     * 开始播放从就绪态到运行态的动画
     */
    public void startReady2RunAnimation(Process process){
        ready2RunRec.setVisible(true);
        ready2RunPt.play();
        try {
            Thread.sleep(380);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始播放从运行态到阻塞队列的动画
     */
    public void startRun2BlockAnimation(){
        run2BlockRec.setVisible(true);
        run2BlockPt.play();
        try {
            Thread.sleep(700);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始播放从运行态到就绪态的动画
     */
    public void startRun2ReadyAnimation(){
        run2ReadyRec.setVisible(true);
        run2ReadyPt.play();
        try {
            Thread.sleep(380);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void startBlock2ReadyAnimation(){
        block2ReadyRec.setVisible(true);
        block2ReadyPt.play();
        try {
            Thread.sleep(700);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public FlowPane getMemoryPane() {
        return memoryPane;
    }

    public ObservableList<Process> getReadyProcessList() {
        return readyProcessList;
    }

    public ObservableList<Process> getBlockingProcessList() {
        return blockingProcessList;
    }

    public ObservableList<Process> getEndingProcessList() {
        return endingProcessList;
    }

    public Label getRunTimeLabel() {
        return runTimeLabel;
    }

    public Executor getPoolExecutor() {
        return poolExecutor;
    }
}